use serde::{Deserialize, Serialize};
use serde_json::to_vec;
use serde_wasm_bindgen::from_value;
use wasm_bindgen::prelude::*;
extern crate simple_excel_writer as excel;
use excel::{Row, ToCellValue, Workbook};
use js_sys::Array;
mod read_excel;
mod md5_compute;

#[derive(Debug, Deserialize, Serialize)]
#[serde(untagged)]
enum Value {
    String(String),
    Number(f64),
}

#[derive(Debug, Deserialize, Serialize)]
struct Item {
    sheet: String,
    list: Vec<Vec<Value>>,
}

#[derive(Debug, Deserialize, Serialize)]
struct Data {
    items: Vec<Item>,
}

// 为枚举类型实现 trait
impl ToCellValue for Value {
    fn to_cell_value(&self) -> simple_excel_writer::CellValue {
        match self {
            Value::String(s) => simple_excel_writer::CellValue::String(s.clone()),
            Value::Number(n) => simple_excel_writer::CellValue::Number(*n),
        }
    }
}
//  Result<Vec<u8>, JsValue>
#[wasm_bindgen]
// pub fn export_excel(text: &str) {
pub fn export_excel(text: &str) -> Result<Vec<u8>, JsValue> {
    let json_data = text;
    // let json_data = r#"
    //  [
    //     {
    //         "sheet":"测试一下",
    //         "list":[
    //         ["1.4",4],
    //         [1,"4"]
    //         ]
    //     },
    //     {
    //         "sheet":"测试喜爱",
    //         "list":[
    //         ["1","4"],
    //         ["1","4"]
    //         ]
    //     }
    //     ]
    // "#;

    // 解析 JSON 字符串
    let data: Vec<Item> = serde_json::from_str(json_data).expect("数据解析失败");
    let mut wb = Workbook::create_in_memory();
    // 打印解析后的数据
    for item in data {
        let mut sheet = wb.create_sheet(&item.sheet);
        let _ = wb.write_sheet(&mut sheet, |sheet_writer| {
            let sw: &mut excel::SheetWriter<'_, '_> = sheet_writer;

            for inner_list in item.list {
                let mut row = Row::new();
                for cell_value in inner_list {
                    row.add_cell(cell_value.to_cell_value());
                }
                let _ = sw.append_row(row);
            }
            Ok(())
        });
    }
    // Option<Vec<u8>>表示可能存在或者不存在
    let buffer: Option<Vec<u8>> = wb.close().expect("close excel error!");
    return buffer
        .map(Ok)
        .unwrap_or_else(|| Err(JsValue::from("Data not found")));
}

#[wasm_bindgen]
pub struct CeshiItem {
    title: String,
    list: Vec<String>,
}
impl CeshiItem {
    pub fn new(title: String, list: Vec<String>) -> Self {
        CeshiItem { title, list }
    }
}
#[wasm_bindgen]
pub struct CeshiData {
    titles: String,
    code: usize,
}

#[wasm_bindgen]
pub fn vec_of_strings_to_js(vec: Vec<String>) -> Array {
    let js_array = Array::new();
    for item in vec {
        js_array.push(&JsValue::from_str(&item));
    }
    js_array
}



#[wasm_bindgen]
impl CeshiData {
    #[wasm_bindgen(constructor)]
    pub fn new(titles: &str, code: usize) -> CeshiData {
        CeshiData {
            titles: titles.to_string(),
            code,
        }
    }
    pub fn get_data(&self) -> Result<String, JsError> {
        return Ok(self.titles.clone());
    }
}

#[wasm_bindgen]
pub struct ImagequantImage {
    pixels: Vec<imagequant::RGBA>,
    width: usize,
    height: usize,
    gamma: f64,
}

#[wasm_bindgen]
impl ImagequantImage {
    /// Make an image from RGBA pixels.
    /// Use 0.0 for gamma if the image is sRGB (most images are).
    #[wasm_bindgen(constructor)]
    pub fn new(data: Vec<u8>, width: usize, height: usize, gamma: f64) -> ImagequantImage {
        let pixels: Vec<imagequant::RGBA> = data
            .chunks(4)
            .map(|chunk| imagequant::RGBA {
                r: chunk[0],
                g: chunk[1],
                b: chunk[2],
                a: chunk[3],
            })
            .collect();

        ImagequantImage {
            pixels,
            width,
            height,
            gamma,
        }
    }
}

#[wasm_bindgen]
pub struct Imagequant {
    instance: imagequant::Attributes,
}

#[wasm_bindgen]
impl Imagequant {
    #[wasm_bindgen(constructor)]
    pub fn new() -> Imagequant {
        Imagequant {
            instance: imagequant::new(),
        }
    }

    /// Make an image from RGBA pixels.
    /// Use 0.0 for gamma if the image is sRGB (most images are).
    pub fn new_image(data: Vec<u8>, width: usize, height: usize, gamma: f64) -> ImagequantImage {
        ImagequantImage::new(data, width, height, gamma)
    }

    /// It's better to use `set_quality()`
    pub fn set_max_colors(&mut self, max_colors: u32) -> Result<(), JsError> {
        self.instance
            .set_max_colors(max_colors)
            .map_err(JsError::from)
    }

    /// Range 0-100, roughly like JPEG.
    ///
    /// If the minimum quality can't be met, the quantization will be aborted with an error.
    ///
    /// Default is min 0, max 100, which means best effort, and never aborts the process.
    ///
    /// If max is less than 100, the library will try to use fewer colors.
    /// Images with fewer colors are not always smaller, due to increased dithering it causes.
    pub fn set_quality(&mut self, minimum: u8, target: u8) -> Result<(), JsError> {
        self.instance
            .set_quality(minimum, target)
            .map_err(JsError::from)
    }

    /// 1-10.
    ///
    /// Faster speeds generate images of lower quality, but may be useful
    /// for real-time generation of images.
    ///
    /// The default is 4.
    pub fn set_speed(&mut self, value: i32) -> Result<(), JsError> {
        self.instance.set_speed(value).map_err(JsError::from)
    }

    /// Number of least significant bits to ignore.
    ///
    /// Useful for generating palettes for VGA, 15-bit textures, or other retro platforms.
    pub fn set_min_posterization(&mut self, value: u8) -> Result<(), JsError> {
        self.instance
            .set_min_posterization(value)
            .map_err(JsError::from)
    }

    /// Create PNG based on specified settings
    pub fn process(&mut self, image: ImagequantImage) -> Result<Vec<u8>, JsError> {
        let ref mut liq_image = self
            .instance
            .new_image(image.pixels, image.width, image.height, image.gamma)
            .map_err(JsError::from)?;

        let mut res = self.instance.quantize(liq_image).map_err(JsError::from)?;

        let (palette, pixels) = res.remapped(liq_image).map_err(JsError::from)?;

        let mut encoder = lodepng::Encoder::new();
        encoder
            .set_palette(palette.as_slice())
            .map_err(JsError::from)?;

        let png_vec: Vec<u8> = encoder
            .encode(pixels.as_slice(), image.width, image.height)
            .map_err(JsError::from)?;

        Ok(png_vec)
    }
}

// map_err 是 Result 类型上的一个方法，用于将 Err 变体中的错误值转换为另一个错误值。这在你需要将一种错误类型转换为另一种错误类型时非常有用
